﻿using System;
using System.Collections.Generic;
using System.Web;
using System.IO;
using System.Text;

namespace AjaxUploadServer
{
	
	public partial class ServerFileManage
	{
		public const string IdFormat = "N";
		public static string NewId()
		{
			return Guid.NewGuid().ToString(IdFormat);
		}
		public static void SavePlainFile(string filename, string contents, Encoding enc)
		{
			if (String.IsNullOrEmpty(contents)) return;

			FileInfo fi = new FileInfo(filename);
			if (!fi.Directory.Exists)
			{
				fi.Directory.Create();
			}
			fi = null;
			File.WriteAllText(filename, contents, enc);
		}
		public static void SavePlainFile(string filename, string contents)
		{
			SavePlainFile(filename, contents, Encoding.UTF8);
		}

		public static string sha1_file(string filename)
		{
			if (String.IsNullOrEmpty(filename) || !File.Exists(filename)) return null;
			var sha1 = System.Security.Cryptography.SHA1.Create();
			byte[] buf;
			using (var reader = File.OpenRead(filename))
			{
				buf = sha1.ComputeHash(reader);
			}
			return BitConverter.ToString(buf).Replace("-", String.Empty).ToLower();
		}
		public static string md5_file(string filename)
		{
			if (String.IsNullOrEmpty(filename) || !File.Exists(filename)) return null;
			var sha1 = System.Security.Cryptography.MD5.Create();
			byte[] buf;
			using (var reader = File.OpenRead(filename))
			{
				buf = sha1.ComputeHash(reader);
			}
			return BitConverter.ToString(buf).Replace("-", String.Empty).ToLower();
		}


		public ServerFileManage(IServerManager server)
		{
			this.server = server;
		}
		private readonly IServerManager server;

		/// <summary>
		/// 上传存储物理路径
		/// </summary>
		public string UploadPath
		{
			get
			{
				var uploadPath = ServerContext.GetValueFromConfigure("UploadBasePath", null);
				uploadPath = ServerContext.GetServerFileName(uploadPath, this.server);
				return uploadPath;
			}
		}

		/// <summary>
		/// 创建本地文件对象
		/// </summary>
		/// <param name="client">客户端文件信息</param>
		/// <returns>IServerFile</returns>
		public IServerFile CreateFile(ClientFile client)
		{
			return new ServerFile(this, client);
		}
		public IServerFile CreateFile(string guid, ClientFile client)
		{
			return new ServerFile(guid, this, client);
		}
		public IServerFile CreateFile(HttpRequestBase request)
		{
			return CreateFile(ClientFile.Create(request));
		}
		public IServerFile CreateFile(Stream stream)
		{
			return CreateFile(ClientFile.Create(stream));
		}
		public IServerFile CreateFile(string json)
		{
			return CreateFile(ClientFile.Create(json));
		}

		public IServerFile GetServerFile(string guid)
		{
			string name = String.Format("{0}.json", guid);
			string fullname = Path.Combine(this.UploadPath, name);
			var client = ClientFile.CreateFromFile(fullname);
			if (client.IsEmpty) return null;
			return CreateFile(guid, client);
		}
	}

	public partial class ServerFileManage
	{
		private class ServerFile : IServerFile
		{
			public ServerFile(string id, ServerFileManage host, ClientFile client)
			{
				this._Id = id;
				this.host = host;
				this._ClientFileInfo = client;
			}
			public ServerFile(ServerFileManage host, ClientFile client) : this(NewId(), host, client)
			{
			}
			private readonly ServerFileManage host;

			public bool IsValid
			{
				get { return !ClientFileInfo.IsEmpty; }
			}

			private readonly string _Id;
			public string Id
			{
				get { return _Id; }
			}

			private string _Hash;
			public string Hash
			{
				get { return _Hash; }
				set { _Hash = value; }
			}

			private readonly ClientFile _ClientFileInfo;
			public ClientFile ClientFileInfo
			{
				get { return _ClientFileInfo; }
			}
			public string InfoName
			{
				get
				{
					var name = String.Format("{0}.json", this.Id);
					return Path.Combine(this.host.UploadPath, name);
				}
			}
			public bool InfoExists
			{
				get { return File.Exists(InfoName); }
			}
			
			public bool SaveInfo(string json)
			{
				var filename = InfoName;
				if (File.Exists(filename)) return true;
				try
				{
					SavePlainFile(filename, json);
					return true;
				}
				catch
				{
					return false;
				}
			}
			public bool SaveInfo()
			{
				return SaveInfo(this.ClientFileInfo.json);
			}

			public string TempName
			{
				get
				{
					var name = String.Format("{0}.tmp", this.Id);
					return Path.Combine(this.host.UploadPath, name);
				}
			}

			public bool SaveTemp(Stream stream)
			{
				try
				{
					var filename = TempName;
					FileInfo fi = new FileInfo(filename);
					if (!fi.Directory.Exists) fi.Directory.Create();
					long pos = 0;
					if (fi.Exists)
					{
						pos = fi.Length;
					}
					byte[] buffer = new byte[stream.Length];
					stream.Read(buffer, 0, buffer.Length);
					using (var writer = fi.OpenWrite())
					{
						writer.Seek(pos, SeekOrigin.Begin);
						writer.Write(buffer, 0, buffer.Length);
						writer.Close();
					}
					return true;
				}
				catch
				{
					return false;
				}
			}
			public bool SaveTemp(HttpRequestBase request)
			{
				return SaveTemp(request.GetBufferlessInputStream());
			}

			public bool CheckHash(string hashType)
			{
				if (String.IsNullOrEmpty(hashType)) return false;
				string hash = null;
				switch(hashType.ToUpper())
				{
					case "SHA1":
						hash = sha1_file(TempName);
						break;
					case "MD5":
						hash = md5_file(TempName);
						break;
				}
				return hash == this.ClientFileInfo.hash;
			}

			public bool Finalize()
			{
				//var info = InfoName;
				try
				{
					var temp = TempName;
					var fin = Path.Combine(this.host.UploadPath, String.Format("{0}.bin", this.Id));

					FileInfo fi = new FileInfo(temp);
					if (!fi.Exists)
					{
						return false;
					}

					fi.MoveTo(fin);
					return true;
				}
				catch
				{
					return false;
				}
			}

		}
	}
}